#include "KCore.h"
#include "WinUtil.h"
#include <stdio.h>

struct DX8State
{
	// win stuff
	HWND hWnd;

	// dx8 stuff
	IDirect3DDevice8* pd3dDevice;

	// callback
	DX8_CREATE_DEVICE_CALLBACK  onCreateDevice;
	DX8_FRAME_RENDER_CALLBACK   onFrameRender;
	DX8_DESTROY_DEVICE_CALLBACK onDestroyDevice;
};

static struct DX8State g_DX8State;


void KCDX8SetCallbackCreateDevice(DX8_CREATE_DEVICE_CALLBACK cb)
{
	g_DX8State.onCreateDevice = cb;
}

void KCDX8SetCallbackFrameRender(DX8_FRAME_RENDER_CALLBACK cb)
{
	g_DX8State.onFrameRender = cb;
}

void KCDX8SetCallbackDeviceDestroyed(DX8_DESTROY_DEVICE_CALLBACK cb)
{
	g_DX8State.onDestroyDevice = cb;
}



//
// Window Message Handler
//

static LRESULT CALLBACK KCDX8WndProc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	switch (message)
	{
	case WM_DESTROY:
		::PostQuitMessage(0);
		return 0;

	case WM_KEYDOWN:
		return 0;

	case WM_LBUTTONDOWN:
		return 0;

	case WM_MOUSEMOVE:
		return 0;
	}

     return DefWindowProc (hWnd, message, wParam, lParam) ;
}

void KCDX8Init()
{

}

void KCDX8CreateWindow(const char *title, int width, int height)
{
	HINSTANCE hInst = ::GetModuleHandle(NULL);
	
	WinClassMaker clsMaker(hInst, "KCore DX8 Demo", KCDX8WndProc);
	clsMaker.Register();

	WinMaker winMaker(hInst, "KCore DX8 Demo");
	winMaker.SetSize(width, height);
	g_DX8State.hWnd = winMaker.Create(title);
}

void KCDX8CreateDevice()
{
	IDirect3D8* pd3d;
	IDirect3DDevice8* pd3dDevice;
	
	pd3d = Direct3DCreate8(D3D_SDK_VERSION);

    // Create the D3DDevice
	HRESULT hr;
	D3DDISPLAYMODE dm;
	hr = pd3d->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &dm);
	KCDX8_HR_FAILCHECK(hr, "pd3d->EnumAdapterModes");

	// Set up the structure used to create the D3DDevice
    D3DPRESENT_PARAMETERS d3dpp;
    ZeroMemory( &d3dpp, sizeof(d3dpp) );
    d3dpp.Windowed = TRUE;
    d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
    d3dpp.BackBufferFormat = dm.Format;

    hr = pd3d->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, g_DX8State.hWnd,
                                      D3DCREATE_HARDWARE_VERTEXPROCESSING,
                                      &d3dpp, &pd3dDevice );
	KCDX8_HR_FAILCHECK(hr, "pd3d->CreateDevice");

	KSAFE_RELEASE(pd3d);

	g_DX8State.pd3dDevice = pd3dDevice;
	g_DX8State.onCreateDevice(pd3dDevice);
}

void KCDX8MainLoop()
{
	HWND hWnd = g_DX8State.hWnd;

	::ShowWindow(hWnd, SW_SHOWNORMAL);
	::UpdateWindow(hWnd);

	MSG msg;
	ZeroMemory(&msg, sizeof(msg));
	while (msg.message != WM_QUIT)
	{
		if (::PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
		{
			::DispatchMessage(&msg);
		}
		else
		{
			g_DX8State.onFrameRender(g_DX8State.pd3dDevice);
		}
	}

	g_DX8State.onDestroyDevice(g_DX8State.pd3dDevice);
	KSAFE_RELEASE(g_DX8State.pd3dDevice);
}

void KCDX8_HR_FAILCHECK(DWORD hr, const char *desc)
{
	if (FAILED(hr))
	{
		char errMsg[256], finalMsg[512];
		D3DXGetErrorString(hr, errMsg, sizeof(errMsg));
		sprintf_s(finalMsg, sizeof(finalMsg), "%s: %s", desc, errMsg);
		MessageBox(NULL, finalMsg, "Error", MB_OK);
		exit(1);
	}
}